from __future__ import annotations
import uvicorn
from fastapi import FastAPI
from typing import List, Optional

from axiom_boot.conf.manager import Settings
from axiom_boot.di.application_context import ApplicationContext
from axiom_boot.di.interfaces import ApplicationProcessor
from axiom_boot.logging.setup import get_logger, setup_logging
from axiom_boot.core.exceptions import register_exception_handlers
from dotenv import load_dotenv

logger = get_logger(__name__)


class AxiomApplication(FastAPI):
    """
    Axiom Boot 应用的唯一公共入口点。

    此类扩展了 FastAPI，并集成了一个完整的依赖注入 (DI) 容器和
    一个可扩展的应用生命周期管理系统。
    """
    context: ApplicationContext

    def __init__(
        self,
        scan_base_packages: Optional[List[str]] = None,
        config_file: Optional[str] = None,
        mode: str = 'web',
        **kwargs
    ):
        """
        初始化 AxiomApplication。

        Args:
            scan_base_packages: 需要进行组件扫描的包路径列表。
            config_file: (可选) 自定义 .env 文件的路径。
            mode: 应用的运行模式 ('web' 或 'worker')。
            **kwargs: 其他所有传递给 FastAPI 父类构造函数的参数 (例如 title, version)。
        """
        # [精准修改] 1. 为了满足 FastAPI 构造函数，临时创建一个 settings
        temp_settings_for_fastapi = Settings(_env_file=config_file)
        
        # 2. 将 settings 中的 app_name, version 等传给 FastAPI 的构造函数
        fastapi_kwargs = {
            'title': temp_settings_for_fastapi.app_name,
            'version': temp_settings_for_fastapi.app_version,
            'debug': temp_settings_for_fastapi.debug,
            **kwargs
        }
        super().__init__(**fastapi_kwargs)
        
        # [精准修改] 3. 立即创建 ApplicationContext，由它来管理真正的 Settings 和 mode
        self.context = ApplicationContext(
            scan_base_packages=scan_base_packages,
            config_file=config_file,
            mode=mode
        )

        # [精准修改] 4. 使用由 context 创建并管理的 settings
        settings = self.context._settings

        # 3. 根据配置，在应用初始化时添加中间件
        # [修改] 增加 run_mode == 'web' 的判断
        if settings.run_mode == 'web':
            if settings.oauth_enabled:
                from axiom_boot.auth.middleware import OAuthMiddleware
                self.add_middleware(OAuthMiddleware)
                logger.info("OAuth 2.0 中间件已成功注册。")
            else:
                logger.info("OAuth 2.0 中间件未启用，跳过注册。")

        # 4. 注册全局异常处理器
        register_exception_handlers(self)

        # 5. 初始化日志系统
        setup_logging(settings)
        logger.info(f"正在构建应用: {settings.app_name}...")

        # 6. 创建应用上下文 (此行已被上面的新逻辑取代，故删除)
        
        # 7. 将应用实例自身注入上下文，这是关键一步
        self.context.set_app(self)

        # 8. 注册 FastAPI 的生命周期事件钩子
        # [修改] 增加 run_mode == 'web' 的判断
        if settings.run_mode == 'web':
            self.add_event_handler("startup", self.on_startup)
            self.add_event_handler("shutdown", self.on_shutdown)
        logger.info("应用骨架构建完成。")

    async def on_startup(self):
        await self.context.refresh()

    async def on_shutdown(self):
        await self.context.close()

    def run(self, **kwargs):
        """启动 Uvicorn 服务器来运行应用。"""
        logger.info("准备启动 Uvicorn 服务器...")
        settings = self.context._settings
        uvicorn_kwargs = {
            "host": settings.host,
            "port": settings.port,
            "log_level": settings.log_level.lower(),
            "reload": settings.reload,
            **kwargs
        }
        # 注意：这里的第一个参数必须是 'app' 实例的导入字符串，或者 app 实例本身。
        # 当直接传递 self 时，Uvicorn 在 reload 模式下可能工作不正常。
        # 但为简单起见，我们暂时直接传递 self。
        uvicorn.run(self, **uvicorn_kwargs)

    @staticmethod
    def run_app(
            scan_base_packages: Optional[list[str]] = None,
            config_file: Optional[str] = None
    ):
        """
        静态工厂方法，用于创建并运行应用。
        提供一个类似于 SpringApplication.run() 的便捷入口。

        此方法会自动处理：
        1. 加载 .env 文件
        2. 创建 AxiomApplication 实例 (包括 FastAPI 和 DI 容器)
        3. 启动 Uvicorn 服务器
        """
        load_dotenv(config_file)
        
        # [精准修改] 不再需要单独创建 settings 来确定扫描路径
        app = AxiomApplication(
            scan_base_packages=scan_base_packages, # ApplicationContext 会处理 None 的情况
            config_file=config_file,
        )
        app.run() 